#include <iostream>
#include <pthread.h>
#include <unistd.h>
#include <string>
#include <cassert>

class Mutex
{
public:
    Mutex(pthread_mutex_t *mtx):pmtx_(mtx)
    {}
    void lock()
    {
        pthread_mutex_lock(pmtx_);
    }
    void unlock()
    {
        pthread_mutex_unlock(pmtx_);
    }

private:
    pthread_mutex_t *pmtx_;
};
class lockguard
{
    private:
    Mutex mtx_;
public:
    lockguard(pthread_mutex_t *mtx):mtx_(mtx)
    {
        mtx_.lock();
    }
    ~lockguard()
    {
        mtx_.unlock();
    }
};

#include <functional>
typedef std::function<int(int,int)> Func;
class Task
{
    public:
    int x_,y_;
    Func func_;
    Task(int x,int y,Func func):x_(x), y_(y), func_(func){}
    int operator()()
    {
        return func_(x_,y_);
    }
};

#define TNUM 3
typedef void(*func_t)(const std::string& name,pthread_mutex_t *pmtx,pthread_cond_t *pcond);
volatile bool quit=false;

class ThreadData
{
public:
    std::string name_;
    pthread_mutex_t *mutex_;
    pthread_cond_t *cond_;
    func_t func_;
    ThreadData(std::string name, func_t func,pthread_mutex_t *mutex, pthread_cond_t *cond)
        : name_(name), func_(func), mutex_(mutex), cond_(cond) {}
};

void func1(const std::string& name,pthread_mutex_t *pmtx,pthread_cond_t *pcond)
{
    while(!quit)
    {
        pthread_mutex_lock(pmtx);
        pthread_cond_wait(pcond,pmtx);
        printf("%s: %d\n",name.c_str(),1);
        pthread_mutex_unlock(pmtx);
        usleep(1000);
    }
}

void func2(const std::string& name,pthread_mutex_t *pmtx,pthread_cond_t *pcond)
{
    while(!quit)
    {
        pthread_mutex_lock(pmtx);
        pthread_cond_wait(pcond,pmtx);
        printf("%s: %d\n",name.c_str(),2);
        pthread_mutex_unlock(pmtx);
        usleep(1000);
    }
}

void func3(const std::string& name,pthread_mutex_t *pmtx,pthread_cond_t *pcond)
{
    while(!quit)
    {
        pthread_mutex_lock(pmtx);
        pthread_cond_wait(pcond,pmtx);
        printf("%s: %d\n",name.c_str(),3);
        pthread_mutex_unlock(pmtx);
        usleep(1000);
    }
}

void func4(const std::string& name,pthread_mutex_t *pmtx,pthread_cond_t *pcond)
{
    while(!quit)
    {
        pthread_mutex_lock(pmtx);
        pthread_cond_wait(pcond,pmtx);
        printf("%s: %d\n",name.c_str(),4);
        pthread_mutex_unlock(pmtx);
        usleep(1000);
    }
}

void* Entry(void* arg)
{
    ThreadData *td=(ThreadData*)arg;
    td->func_(td->name_,td->mutex_,td->cond_);
    delete td;
    return nullptr;
}
int main()
{
    pthread_mutex_t mtx;
    pthread_cond_t cond;
    pthread_mutex_init(&mtx, nullptr);
    pthread_cond_init(&cond, nullptr);
    pthread_t tids[TNUM];
    func_t funcs[]={func1,func2,func3,func4};
        
    for (int i = 0; i < TNUM; i++)
    {
        std::string name="thread"+std::to_string(i+1);
        ThreadData *td=new ThreadData(name,funcs[i],&mtx,&cond);
        pthread_create(&tids[i], nullptr, Entry, (void*)td);
    }
    sleep(2);
    int n=3;
    while(n--)
    {
        std::cout<<"call up"<<std::endl;
        pthread_cond_broadcast(&cond);
        sleep(1);
    }
    std::cout<<"call down"<<std::endl;
    quit=true;
    pthread_cond_broadcast(&cond);
    for (int i = 0; i < TNUM; i++)
    {
        pthread_join(*(tids+i), nullptr);
        std::cout<<"thread "<<tids[i]<<" exit"<<std::endl;
    }
    pthread_mutex_destroy(&mtx);
    pthread_cond_destroy(&cond);
    return 0;
}


// #define THREAD_NUM 3
//  int tickets = 10000;

// class ThreadData
// {
// public:
//     std::string name_;
//     pthread_mutex_t *mutex_;
//     ThreadData(std::string name, pthread_mutex_t *mutex)
//         : name_(name), mutex_(mutex) {}
// };
// void *getTickets(void *arg)
// {
//     ThreadData *td = (ThreadData *)arg;
//     while (true)
//     {
//         int n = pthread_mutex_lock(td->mutex_);
//         assert(n == 0);
//         if (tickets > 0)
//         {
//             printf("%s: %d\n", td->name_.c_str(), tickets);
//             tickets--;
//             n = pthread_mutex_unlock(td->mutex_);
//             assert(n == 0);
//         }
//         else
//         {
//             n = pthread_mutex_unlock(td->mutex_);
//             assert(n == 0);
//             break;
//         }
//         usleep(rand()%2000);
//     }
//     delete td;
//     return nullptr;
// }
// int main()
// {
//     time_t start = time(nullptr);
//     pthread_mutex_t mutex;
//     pthread_mutex_init(&mutex, nullptr);

//     srand(time(nullptr));

//     pthread_t threads[THREAD_NUM];
//     for (int i = 0; i < THREAD_NUM; i++)
//     {
//         std::string name = "thread" + std::to_string(i + 1);
//         ThreadData *td = new ThreadData(name, &mutex);
//         pthread_create(&threads[i], nullptr, getTickets, (void *)td);
//     }
//     for (int i = 0; i < THREAD_NUM; i++)
//     {
//         pthread_join(threads[i], nullptr);
//     }
//     pthread_mutex_destroy(&mutex);
//     time_t end = time(nullptr);
//     std::cout << "time:" << end - start << std::endl;
//     return 0;
// }

// int global_var = 0;
// void *increment_count(void *arg)
// {
//     for (int i = 0; i < 10000000; i++)
//     {
//         global_var++;
//         std::cout << global_var << std::endl;
//         usleep(10000);
//     }
//     return NULL;
// }

// int ticket = 111;

// void *getTickets(void *arg)
// {
//     while(true)
//     {
//         if(ticket > 0)
//         {
//             printf("%#lx: %d\n", pthread_self(),ticket);
//             ticket--;
//         }else{break;}
//         usleep(1000);
//     }
//     return NULL;
// }

// int main()
// {
//     pthread_t t1, t2, t3;
//     pthread_mutex_t mutex;
//     // 创建三个线程
//     pthread_create(&t1, nullptr, getTickets, nullptr);
//     pthread_create(&t2, nullptr, getTickets, nullptr);
//     pthread_create(&t3, nullptr, getTickets, nullptr);

//     // 等待所有线程执行完毕
//     pthread_join(t1, nullptr);
//     pthread_join(t2, nullptr);
//     pthread_join(t3, nullptr);

//     // 输出最后剩余的票数（在实际运行中可能不准确，因为存在竞态条件）
//     std::cout << "最终剩余票数: " << ticket << std::endl;

//     return 0;
// }
// int main()
// {
//     pthread_t threads[2];
//     for (int i = 0; i < 2; i++)
//     {
//         if (pthread_create(&threads[i], NULL, increment_count, NULL))
//         {
//             std::cerr << "Error creating thread" << std::endl;
//             return 1;
//         }
//     }

//     for (int i = 0; i < 2; i++)
//     {
//         pthread_join(threads[i], NULL);
//     }
//     std::cout << "Final count: " << global_var << std::endl;
//     return 0;
// }